import { default as axios } from 'axios'
import router from '@/router/router'
import store from '@/store/index'
import Vue from 'vue'
import { registerPending, requestDone, RegisterType as _RegisterType } from '@/util/cancelToken'
import { Cancelable, Logable, UseServise_1P, UseLocal } from './useRequest'
import { cancelRequestWrap } from './cancelRequestWrap'

export const Instance = axios.create({
  baseURL: process.env.VUE_APP_DATAURL,
  timeout: 1000 * 60
})

Instance.use = function(fn) {
  const realFn = fn.bind(this)
  const newFn = (...args) => realFn(...args)
  newFn.use = this.use
  return newFn
}

export const $cancelable =
Instance
  .use(Logable)
  .use(Cancelable)

export const $use_1p_servise =
Instance
  .use(Logable)
  .use(UseServise_1P)

export const $local =
Instance
  .use(Logable)
  .use(UseLocal)

// 是否正在刷新的标志
let isTokenRefreshing = false
// 存储请求的数组
let subscribesArr = []

// 请求push到数组中
function subscribesArrRefresh(cb) {
  subscribesArr.push(cb)
}

// 用新token发起请求
function reloadSubscribesArr(newToken) {
  subscribesArr.map((cb) => cb(newToken))
}

function isTokenExpire(serverTokenExpire) {
  const timestmp = new Date().getTime()
  return timestmp >= serverTokenExpire
}

Instance.canclePromise = null
Instance.interceptors.request.use(
  function(config) {
    if (config.url && config.url.includes('contentAnalyzer/analyzingAsin')) {
      config.timeout = 1000 * 60 * 60
    }
    // 判断token是否过期
    // get参数编码
    config.headers.Authorization =
      'Bearer ' + (window.localStorage.getItem('ac') || '').slice(2)
    if (config.method === 'get' && config.params) {
      config.url += '?'
      const keys = Object.keys(config.params)
      for (const key of keys) {
        config.url += `${key}=${encodeURIComponent(config.params[key])}&`
      }
      config.url = config.url.substring(0, config.url.length - 1)
      config.params = {}
    }
    if (config.url.includes(process.env.VUE_APP_TAGURL)) {
      config.headers.productLine = process.env.VUE_APP_TAGNAME
    }
    if (config.url.includes('refreshToken') || config.url.includes('Login')) {
      return config
    }
    config.headers.webfrom = '3'
    const serverTokenExpire = window.localStorage.getItem('exptime')
    if (serverTokenExpire && isTokenExpire(serverTokenExpire)) {
      // 判断token是否已经刷新过
      if (!isTokenRefreshing) {
        isTokenRefreshing = true
        // 请求刷新token
        delete config.headers.Authorization
        axios
          .get(process.env.VUE_APP_BASEURL + 'Login/refreshToken', {
            params: {
              refreshToken: localStorage.getItem('re').slice(2)
            },
            headers: {
              authorization: ''
            }
          })
          .then((res) => {
            // loading.close()
            isTokenRefreshing = false
            if (res.data.data.isError) {
              subscribesArr = []
              localStorage.removeItem('exptime')
              localStorage.removeItem('ac')
              localStorage.removeItem('re')
              router.push('/Login')
            } else {
              store.commit('userInfo/$_refreshToken', {
                accessToken: res.data.data.accessToken,
                refreshToken: res.data.data.refreshToken,
                expiresIn: res.data.data.expiresIn
              })
              reloadSubscribesArr(res.data.data.accessToken)
            }
          })
          .catch((err) => {
            console.log(err)
            isTokenRefreshing = false
            subscribesArr = []
            router.push('/Login')
          })
      }
      const retry = new Promise((resolve) => {
        subscribesArrRefresh((newToken) => {
          Instance.defaults.headers.common['Authorization'] =
            'Bearer ' + newToken
          config.headers.Authorization = 'Bearer ' + newToken
          resolve(config)
        })
      })
      return retry
    }
    registerPending(config)
    /*
      // method : put
      // content-type: application/json
      // data JSONString -> Object
      if (config.method.toUpperCase() === 'PUT' &&
          config.headers['Content-Type'].indexOf('application/json') !== -1 &&
          config.data &&
          typeof config.data === 'string'
      ) {
        config.data = JSON.parse(config.data)
      }
    */
    // console.log(config)
    return config
  },
  (err) => {
    return Promise.reject(err)
  }
)

Instance.interceptors.response.use(
  function(res) {
    requestDone(res.config)
    const link = res.config.url.split('api')[2] || []
    if (
      link.includes('isExport') &&
      res.headers['content-type'].includes('json')
    ) {
      return Promise.resolve(res)
    }
    if (
      (res.data == null || res.data.data == null) &&
      link === '/Report/customTablePlan'
    ) {
      return Promise.resolve('[]')
    }
    // if (res.config.url.lastIndexOf('usage/api/status') === -1) {
    //   return Promise.resolve('[]')
    // }
    if (res.data.code && res.data.code !== 200) {
      // Vue.prototype.$pacLoading('hide')
      // Vue.prototype.$message.error(res.data.msg)
      return Promise.reject(res)
    } else {
      if (res.config.method === 'delete') {
        if (!res.config.headers.noMessage) {
          Vue.prototype.$message.success('Delete Successfully.')
        }
        return Promise.resolve(res.data.code)
      } else {
        // 是否是下载
        if (res.headers['content-disposition']) {
          const disposition = res.headers['content-disposition']
          const fileName = disposition.substring(
            disposition.indexOf('filename=') + 9,
            disposition.length
          )
          return Promise.resolve({
            fileName,
            blob: res.data
          })
        } else {
          return Promise.resolve(res.data)
        }
      }
    }
  },
  (err) => {
    if (!axios.isCancel(err)) {
      let errMsg = ''
      // 网络超时
      if (err.code === 'ECONNABORTED') {
        // Vue.prototype.$message.error('Network Error: Network Timeout')
        errMsg = 'Network Error: Network Timeout'
      } else {
        if (err.response) {
          if (err.response.status === 401) {
            // 捕捉token过期时,跳转到登录页
            console.warn('The token has expired and will jump to the login page')
            router.push('/Login')
          } else if (err.response.status === 403) {
            // Vue.prototype.$message.error('Network Error: You do not have permission to complete the operation.')
            errMsg = 'Network Error: You do not have permission to complete the operation.'
          } else {
            // 其他异常状态码错误
            if (process.env.NODE_ENV !== 'production') {
              // Vue.prototype.$message.error(`Network Error: [ ${err.response.data.path || 'unknow path'} ] ${err.response.data.error || 'unknow error'}`)
              errMsg = `Network Error: [ ${err.response.data.path || 'unknow path'} ] ${err.response.data.error || 'unknow error'}`
            } else {
              // Vue.prototype.$message.error(`Network Error: ${err.response.data.error || 'unknow error'}`)
              errMsg = `Network Error: ${err.response.data.error || 'unknow error'}`
            }
          }
        }
      }
      // 配置项表头配置 noErrorTip 控制是否错误提示
      if (errMsg && !err?.config?.headers?.noErrorTip) {
        Vue.prototype.$message.error(errMsg)
      }
      return Promise.reject(err)
    } else {
      // 如果是应用 cancelRequestWrap 返回错误对象
      if (err?.message === 'CANCEL') {
        return Promise.reject(err)
      }
      return new Promise(() => {})
    }
  }
)

export const $instance = Instance

// 可取消请求实例
export const requestOfCallCancel = cancelRequestWrap(Instance, {
  headers: {
    'platform-type': 3
  }
})
// 针对不同 baseURL
export const requestOfCallCancel_3p = requestOfCallCancel
export const requestOfCallCancel_1p = cancelRequestWrap(Instance, {
  baseURL: process.env.VUE_APP_DATAURL_1P,
  headers: {
    'platform-type': 3
  }
})
export const RegisterType = _RegisterType
